package com.sl.core.engine.plugin;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.*;
import com.sl.core.domain.dto.ProcessComponentDTO;
import com.sl.core.engine.annotations.Comp;
import com.sl.core.engine.plugin.domain.PluginDecorate;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.hop.core.plugins.IPlugin;
import org.apache.hop.core.plugins.IPluginType;
import org.apache.hop.core.plugins.PluginRegistry;
import org.apache.hop.core.plugins.TransformPluginType;
import org.springframework.core.annotation.AnnotationUtils;

import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.sl.core.engine.plugin.ProcessPluginLoaderManager.LATEST_TAG;

@Slf4j
public class ProcessPluginRegistry {

    public static ProcessPluginRegistry INSTANCE = new ProcessPluginRegistry();

    private static final String SQUARE_LATE_LABEL = "SQUARE_LATE-";


    @SneakyThrows
    public void registry(Map<String, List<PluginDecorate>> loader) {

        //开始注册插件
        if (CollUtil.isEmpty(loader)) {
            return;
        }

        for (Map.Entry<String, List<PluginDecorate>> entry : loader.entrySet()) {
            String k = entry.getKey();
            List<PluginDecorate> v = entry.getValue();
            if (ObjectUtil.isNull(v)) {
                continue;
            }


            for (int i = 0; i < v.size(); i++) {
                PluginDecorate pluginDecorate = v.get(i);
                registerByPluginDecorate(pluginDecorate, i == v.size() - 1);
            }
        }
    }

    public void registerByPluginDecorate(PluginDecorate pluginDecorate, Boolean latest) {
        ClassLoader classLoader = pluginDecorate.getClassLoader();
        String metaClass = pluginDecorate.getMetaClass();
        String pluginCode = pluginDecorate.getPluginCode();
        if (StrUtil.isBlank(metaClass)) {
            return;
        }
        log.info("开始注册插件[" + pluginCode + "]");

        Class<?> objectClass = ClassLoaderUtil.loadClass(metaClass, classLoader, true);
        //装载
        Comp step = AnnotationUtils.findAnnotation(objectClass, Comp.class);
        //如果是step插件类型
        if (ObjectUtil.isNotNull(step)) {
            pluginDecorate.setGroupName(step.groupName());
            pluginDecorate.setIcon(step.icon());
            pluginDecorate.setPluginName(step.name());
            pluginDecorate.setPluginCode(step.id());
            pluginDecorate.setDesc(step.desc());
            pluginDecorate.setVersion(step.version());
        }
        ProcessStepPluginType.getInstance().register(pluginDecorate.getOrgId(), objectClass, pluginDecorate.getGroupName(), pluginDecorate.getPluginCode(), pluginDecorate.getVersion(), latest, SQUARE_LATE_LABEL + pluginDecorate.getPluginName(), pluginDecorate.getDesc(), pluginDecorate.getIcon());

    }


    public ByteArrayInputStream getSourceCode(String orgId, String pluginCode, String pluginVersion) {
        return ProcessPluginLoaderManager.INSTANCE.getResourceCode(orgId, pluginCode, pluginVersion);

    }

    public static String getId(String orgId, String code, String version) {
        return StrUtil.concat(true, orgId, "@", code, "@", version, "@");
    }

    public List<ProcessComponentDTO> list() {
        List<ProcessComponentDTO> list = Lists.newArrayList();
        Map<String, List<PluginDecorate>> pluginStoreMap = ProcessPluginLoaderManager.INSTANCE.loader();

        for (Map.Entry<String, List<PluginDecorate>> se : pluginStoreMap.entrySet()) {
            String key = se.getKey();
            List<PluginDecorate> value = se.getValue();

            if (CollUtil.isEmpty(value)) {
                continue;
            }
            //取第一个就行了，只是为了拿数据
            PluginDecorate pluginDecorate = CollUtil.get(value, 0);
            ProcessComponentDTO processComponentDTO = new ProcessComponentDTO();
            processComponentDTO.setName(pluginDecorate.getPluginName());
            processComponentDTO.setGroupName(pluginDecorate.getGroupName());
            processComponentDTO.setGroupCode(pluginDecorate.getGroupCode());
            processComponentDTO.setDescription(pluginDecorate.getDesc());
            processComponentDTO.setIcon(pluginDecorate.getIcon());
            processComponentDTO.setPluginCode(pluginDecorate.getPluginCode());
            processComponentDTO.setType(pluginDecorate.getPluginCode());
            processComponentDTO.setSystemFlag(pluginDecorate.getSystemFlag());
            list.add(processComponentDTO);
        }
        return list;
    }


    public List<Map<String, Object>> getVersionList(String orgId, String code) {
//        List<Map<String, Object>> res = Lists.newArrayList();
        List<PluginDecorate> pluginDecorates = ProcessPluginLoaderManager.INSTANCE.matchPluginList(code);

        List<Map<String, Object>> collect = pluginDecorates.stream().filter(v -> {
            return ObjectUtil.equal(v.getOrgId(), orgId) || v.getSystemFlag();
        }).map(v -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("version", v.getVersion());
            map.put("label", v.getVersion());
            map.put("pluginCode", code);
            map.put("systemFlag", v.getSystemFlag());
            map.put("orgId", v.getOrgId());
            map.put("id", getId(v.getOrgId(), code, v.getVersion()));
            return map;
        }).collect(Collectors.toList());


        Map<String, Object> last = CollUtil.getLast(collect);

        Map<String, Object> map = new LinkedHashMap<>();
        map.put("version", LATEST_TAG);
        map.put("label", LATEST_TAG);
        map.put("orgId", orgId);

        if (MapUtil.isNotEmpty(last)) {
            map.put("systemFlag", last.get("systemFlag"));
        } else {
            map.put("systemFlag", true);
        }

        map.put("pluginCode", code);
        map.put("id", code);
        collect.add(0, map);
        return collect;
    }

    public void removePlugin(String id) {
        Class<? extends IPluginType> pluginType = TransformPluginType.class;
        IPlugin pluginWithId = PluginRegistry.getInstance().findPluginWithId(pluginType, id);
        if (ObjectUtil.isNotNull(pluginWithId)) {
            PluginRegistry.getInstance().removePlugin(pluginType, pluginWithId);
        }
    }
}
